package bk

import (
	"dgo/goutils/utils"
	"io"
	"net/url"
	"sort"
	"strings"
	"time"
)

type StrMap map[string]string

func NewStrMap0() StrMap {
	return make(StrMap)
}

func NewStrMapEx(s, kvsep, itmsep string) StrMap {
	r := make(StrMap)
	r.ParseKVPairs(s, kvsep, itmsep)
	return r
}

func NewStrMap(s, itmsep string) StrMap {
	r := make(StrMap)
	r.ParseKVPairs(s, "=", itmsep)
	return r
}

func (this StrMap) Reset() {
	for k := range this {
		delete(this, k)
	}
}

// ExecReplace 利用映射关系进行替换， key -> value
func (this StrMap) ExecReplace(s string) string {
	for k, v := range this {
		s = utils.ReplaceAll(s, k, v)
	}
	return s
}

func (this StrMap) SortRange(fn func(k, v string) bool) {
	if this == nil {
		return
	}
	keys := make([]string, 0, len(this))
	for k := range this {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	for _, k := range keys {
		v := this[k]
		if !fn(k, v) {
			break
		}
	}
}

func (this StrMap) SortRangeEncode(kvspliter string, itmspliter string, fn func(k, v string) bool) string {
	if this == nil {
		return ""
	}
	var buf strings.Builder
	this.SortRange(func(k, v string) bool {
		if fn(k, v) {
			if buf.Len() > 0 {
				buf.WriteString(itmspliter)
			}
			buf.WriteString(k)
			buf.WriteString(kvspliter)
			buf.WriteString(v)
		}
		return true
	})
	return buf.String()

}

func (this StrMap) Encode(kvspliter string, itmspliter string) string {
	if this == nil {
		return ""
	}
	var buf strings.Builder
	keys := make([]string, 0, len(this))
	for k := range this {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	for _, k := range keys {
		if buf.Len() > 0 {
			buf.WriteString(itmspliter)
		}
		v := this[k]
		buf.WriteString(k)
		buf.WriteString(kvspliter)
		buf.WriteString(v)
	}
	return buf.String()
}

func MapEncode(strMap map[string]string, kvsep, itmsep string, escapeflag bool, bb io.Writer) {
	keys := make([]string, 0, len(strMap))
	for k := range strMap {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	i := 0
	for _, k := range keys {
		v := strMap[k]
		if i > 0 {
			bb.Write([]byte(itmsep))
		}
		if escapeflag {
			keyEscaped := url.QueryEscape(k)
			bb.Write([]byte(keyEscaped))
			bb.Write([]byte(kvsep))
			bb.Write([]byte(url.QueryEscape(v)))
		} else {
			bb.Write([]byte(k))
			bb.Write([]byte(kvsep))
			bb.Write([]byte(v))
		}
		i++
	}
}

func (this StrMap) URLFormEncode() string {
	if this == nil {
		return ""
	}
	var buf strings.Builder
	keys := make([]string, 0, len(this))
	for k := range this {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	for _, k := range keys {
		v := this[k]
		keyEscaped := url.QueryEscape(k)
		if buf.Len() > 0 {
			buf.WriteByte('&')
		}
		buf.WriteString(keyEscaped)
		buf.WriteByte('=')
		buf.WriteString(url.QueryEscape(v))
	}
	return buf.String()
}

func (this StrMap) URLFormDecode(s string) {
	lst := strings.Split(s, "&")
	if len(lst) == 0 {
		return
	}
	for i := 0; i < len(lst); i++ {
		k, v := utils.Split2Str(lst[i], "=")
		k, _ = url.QueryUnescape(k)
		v, _ = url.QueryUnescape(v)
		if len(k) > 0 {
			this[k] = v
		}
	}
}

func (this StrMap) CopyFrom(src StrMap) {
	for k, v := range src {
		this[k] = v
	}
}

func (this StrMap) ParseKVPairsEx(s string, kvsep string, itmsep string, keylower bool) {
	lst := strings.Split(s, itmsep)
	if len(lst) == 0 {
		return
	}

	for i := 0; i < len(lst); i++ {
		k, v := utils.Split2Str(lst[i], kvsep)
		if len(k) > 0 {
			if keylower {
				k = strings.ToLower(k)
			}
			this[k] = v
		}
	}
}

func (this StrMap) ParseKVPairs(s string, kvsep string, itmsep string) {
	lst := strings.Split(s, itmsep)
	if len(lst) == 0 {
		return
	}

	for i := 0; i < len(lst); i++ {
		k, v := utils.Split2Str(lst[i], kvsep)
		if len(k) > 0 {
			this[k] = v
		}
	}
}

func (this StrMap) StringByName(k string, def string) string {
	if v, ok := this[k]; ok {
		return v
	} else {
		return def
	}
}

func (this StrMap) IntByName(k string, def int) int {
	if v, ok := this[k]; ok {
		if len(v) == 0 {
			return def
		}
		return utils.StrToIntDef(v, def)
	} else {
		return def
	}
}

func (this StrMap) Float64ByName(k string, def float64) float64 {
	if v, ok := this[k]; ok {
		return utils.StrToFloat64Def(v, def)
	} else {
		return def
	}
}

func (this StrMap) U8ByName(k string, def byte) byte {
	return byte(this.IntByName(k, int(def)))
}

func (this StrMap) Int8ByName(k string, def int8) int8 {
	return int8(this.IntByName(k, int(def)))
}

func (this StrMap) Int16ByName(k string, def int16) int16 {
	return int16(this.IntByName(k, int(def)))
}

func (this StrMap) UnixTimeByName(k string, def time.Time) time.Time {
	v := this.IntByName(k, -99999)
	if v == -99999 {
		return def
	} else {
		return time.Unix(int64(v), 0)
	}
}

/*
解析命令行
XX.exe -a=v
*/
func (this StrMap) ParseCmdArgs(args []string) {
	for i := 0; i < len(args); i++ {
		s1, s2 := utils.Split2Str(args[i], "=")

		if len(s1) > 0 {
			if s1[0] == '-' {
				s1 = s1[1:]
			}
			if len(s2) == 0 {
				s2 = s1
				if i == 0 {
					this["0"] = s1
				} else {
					this[s1] = s2
				}
			} else {
				_, s2 = utils.CheckTrimQuoteChr(s2, utils.QUOTECHR, utils.QUOTECHR)
				this[s1] = s2
			}
		}
	}
}
